package crawler.model;

import business.service.MongoDbFactory;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import crawler.common.CommonUtil;
import crawler.common.UserData;
import crawler.common.UserType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.bson.types.ObjectId;

/**
 *
 * @author vietph
 */
public class UserModel {

    private static final String USER_COLLECTION = "users";

    private static UserModel instance = null;
    private static final Lock iLock = new ReentrantLock();
    protected final Logger logger = Logger.getLogger(this.getClass());

    public static UserModel getInstance() {
        iLock.lock();
        try {
            if (instance == null) {
                instance = new UserModel();
            }
            return instance;
        } finally {
            iLock.unlock();
        }
    }

    public UserModel() {
        try {
        } catch (Exception e) {
            logger.error("UserModel.constructor: " + e.getMessage());
        }
    }

    public UserData getUserByName(String username) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("user", username);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String id = ((ObjectId) dbObject.get("_id")).toString();
                String password = (String) dbObject.get("pass");
                int type = (int) dbObject.get("type");
                String access = (String) dbObject.get("access");
                List<String> lstAccess = new ArrayList<>();
                if (access != null && !access.equalsIgnoreCase("")) {
                    lstAccess.addAll(Arrays.asList(access.split("\\s*,\\s*")));
                }
                long created = (long) dbObject.get("created");
                UserData userData = new UserData(id, username, password, UserType.getById(type), lstAccess, created);

                return userData;
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserByName: " + ex.getMessage(), ex);
        }
        return null;
    }

    public UserData getUserById(String id) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", new ObjectId(id));
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String username = (String) dbObject.get("user");
                String password = (String) dbObject.get("pass");
                int type = (int) dbObject.get("type");
                String access = (String) dbObject.get("access");
                List<String> lstAccess = new ArrayList<>();
                if (access != null && !access.equalsIgnoreCase("")) {
                    lstAccess.addAll(Arrays.asList(access.split("\\s*,\\s*")));
                }
                long created = (long) dbObject.get("created");
                UserData userData = new UserData(id, username, password, UserType.getById(type), lstAccess, created);

                return userData;
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUserById: " + ex.getMessage(), ex);
        }
        return null;
    }

    public String addUser(UserData userData) {
        String id = "";
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("user", userData.getUsername())
                    .append("pass", userData.getPasswdMD5())
                    .append("type", userData.getType().getId())
                    .append("created", userData.getCreated());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            coll.insert(basicDBObject);

            ObjectId objectId = (ObjectId) basicDBObject.get("_id");
            id = objectId.toString();
        } catch (Exception ex) {
            logger.error("UserModel.addUser: " + ex.getMessage());
        }
        return id;
    }

    public boolean deleteUser(String id) {
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            coll.remove(new BasicDBObject("_id", new ObjectId(id)));

            return true;
        } catch (Exception ex) {
            logger.error("UserModel.deleteUser: " + ex.getMessage(), ex);
        }
        return false;
    }

    public boolean updateUser(UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("type", userData.getType().getId());
            if(!userData.getPasswdMD5().isEmpty())
                basicDBObject.append("pass", userData.getPasswdMD5());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);

            BasicDBObject updateDBObject = new BasicDBObject("$set", basicDBObject);
            BasicDBObject searchDBQuery = new BasicDBObject("_id", new ObjectId(userData.getId()));
            coll.update(searchDBQuery, updateDBObject);
            return true;
        } catch (Exception ex) {
            logger.error("UserModel.updateUser: " + ex.getMessage());
        }
        return false;
    }
    
    public boolean updateUserPass(UserData userData) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject()
                    .append("pass", userData.getPasswdMD5());

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);

            BasicDBObject updateDBObject = new BasicDBObject("$set", basicDBObject);
            BasicDBObject searchDBQuery = new BasicDBObject("_id", new ObjectId(userData.getId()));
            coll.update(searchDBQuery, updateDBObject);
            return true;
        } catch (Exception ex) {
            logger.error("UserModel.updateUserPass: " + ex.getMessage());
        }
        return false;
    }

    public List<UserData> getUser(int start, int limit) {
        List<UserData> lstUser = null;
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", -1);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find().sort(basicDBObject);
            if (limit != -1) {
                cursor = cursor.skip(start).limit(limit);
            }
            lstUser = new ArrayList<>();
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String id = ((ObjectId) dbObject.get("_id")).toString();
                String username = (String) dbObject.get("user");
                String password = (String) dbObject.get("pass");
                int type = (int) dbObject.get("type");
                String access = (String) dbObject.get("access");
                List<String> lstAccess = new ArrayList<>();
                if (access != null && !access.equalsIgnoreCase("")) {
                    lstAccess.addAll(Arrays.asList(access.split("\\s*,\\s*")));
                }
                long created = (long) dbObject.get("created");

                UserData userData = new UserData(id, username, password, UserType.getById(type), lstAccess, created);
                lstUser.add(userData);
            }
        } catch (Exception ex) {
            logger.error("UserModel.getUser: " + ex.getMessage(), ex);
        }
        return lstUser;
    }

    public long getTotalUser() {
        long count = 0;
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            count = coll.getCount();
        } catch (Exception ex) {
            logger.error("UserModel.getTotalUser: " + ex.getMessage(), ex);
        }
        return count;
    }

    public boolean validateUser(String username, String password) {
        try {
            if ("admin".equals(username) && "123".equals(password)) {
                return true;
            }
            username = username.toLowerCase();
            password = CommonUtil.md5(password);

            BasicDBObject basicDBObject = new BasicDBObject("user", username)
                    .append("pass", password);

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                return true;
            }
        } catch (Exception ex) {
            logger.error("UserModel.validateUser: " + ex.getMessage(), ex);
        }
        return false;
    }

    public List<String> getUserAccess(String id) {
        List<String> lstAccess = null;
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", new ObjectId(id));
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(USER_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                String access = (String) dbObject.get("access");
                lstAccess = new ArrayList<>();
                if (access != null && !access.equalsIgnoreCase("")) {
                    lstAccess.addAll(Arrays.asList(access.split("\\s*,\\s*")));
                }
            }
        } catch (Exception e) {
            logger.error("UserModel.getUserAccess: " + e.getMessage(), e);
        }
        return lstAccess;
    }

    public boolean updateUserAccess(String id, String access) {
            try {
                BasicDBObject basicDBObject = new BasicDBObject()
                    .append("access", access);

                DB db = MongoDbFactory.getConnection();
                DBCollection coll = db.getCollection(USER_COLLECTION);

                BasicDBObject updateDBObject = new BasicDBObject("$set", basicDBObject);
                BasicDBObject searchDBQuery = new BasicDBObject("_id", new ObjectId(id));
                coll.update(searchDBQuery, updateDBObject);
                return true;
            } catch (Exception ex) {
                logger.error("UserModel.updateUserAccess: " + ex.getMessage());
            }
            return false;
    }

}
